{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dc4c1354-bf95-4ad6-9197-64cac3fa1111",
   "metadata": {},
   "source": [
    "# Front-End Communication (or Supporting Widgets)\n",
    "\n",
    "See detailed documentation in `docs/FrontEndCommunication.md`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "82c87035-c921-4175-adee-176fb3ea2568",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "%goflags=[\"--cover\" \"--covermode=set\"]\n"
     ]
    }
   ],
   "source": [
    "%goflags --cover --covermode=set"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "991075d2-cb0e-4c17-97ec-64174d69b9df",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ok\n"
     ]
    }
   ],
   "source": [
    "!if [[ \"${GONB_GIT_ROOT}\" == \"\" ]] ; then \\\n",
    "    echo \"Please set GONB_GIT_ROOT before runnig this notebook!\" 1>&2 ; \\\n",
    "else \\\n",
    "    echo \"ok\" ; \\\n",
    "fi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "79012c7d-ff26-4dc8-b9f5-684e09d49039",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\t- Added replace rule for module \"github.com/janpfeifer/gonb\" to local directory \"/home/janpf/Projects/gonb\".\n"
     ]
    }
   ],
   "source": [
    "!*rm -f go.work && go work init && go work use . \"${GONB_GIT_ROOT}\"\n",
    "%goworkfix"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2eb2004a-043b-4042-b969-700bce6e3591",
   "metadata": {},
   "source": [
    "### Test Initialization of WebSocket"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "7a871fdb-6b3e-4234-80d1-786c3ee36e2e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": []
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%widgets"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a2ecd95-60f6-4c65-8117-662220a250e1",
   "metadata": {},
   "source": [
    "### Send incrementing counter back-and-forth to front-end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0bc8019a-ee78-4e9a-a603-3de6b5915b0b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": []
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sent 1\n",
      "got 2\n",
      "sent 2\n",
      "got 3\n",
      "sent 3\n",
      "got 4\n",
      "sent 4\n",
      "closed\n",
      "done\n"
     ]
    }
   ],
   "source": [
    "import (\n",
    "    \"github.com/janpfeifer/gonb/gonbui/comms\"\n",
    "    \"github.com/janpfeifer/gonb/gonbui/dom\"\n",
    "\n",
    "    \"log\"\n",
    "    \"os\"\n",
    "    \"time\"\n",
    ")\n",
    "\n",
    "const (\n",
    "    toFrontEnd = \"/nbtest/to_frontend\"\n",
    "    toCell = \"nbtest/to_cell\"\n",
    ")\n",
    "\n",
    "%%\n",
    "listen := comms.Listen[int](toCell)\n",
    "\n",
    "// Small javascript value that receives a number, increments and sends\n",
    "// it back.\n",
    "dom.TransientJavascript(\n",
    "            fmt.Sprintf(`\n",
    "(() => {\n",
    "    let gonb_comm = globalThis?.gonb_comm;\n",
    "    if (gonb_comm) {\n",
    "        var subscrition_id;\n",
    "        let id = gonb_comm.subscribe(\"%s\", (address, value) => {\n",
    "            if (value >= 3) {\n",
    "                gonb_comm.unsubscribe(subscription_id);\n",
    "            }\n",
    "            console.log(address+\"->\"+value);\n",
    "            value = value + 1;\n",
    "            gonb_comm.send(\"%s\", value);\n",
    "        });\n",
    "        subscription_id = id;\n",
    "    }\n",
    "})();\n",
    "`, toFrontEnd, toCell))\n",
    "\n",
    "// Send sequence of numbers to frond-end.\n",
    "go func() {\n",
    "    time.Sleep(1 * time.Second)\n",
    "    for ii := 1; ii < 5; ii++ {\n",
    "        time.Sleep(300 * time.Millisecond)\n",
    "        fmt.Printf(\"sent %d\\n\", ii);\n",
    "        comms.Send(toFrontEnd, ii)        \n",
    "    }\n",
    "}()\n",
    "\n",
    "// Print out replies.\n",
    "for counter := range listen.C {\n",
    "    fmt.Printf(\"got %d\\n\", counter)\n",
    "    if counter >= 4 {\n",
    "        break\n",
    "    }\n",
    "}\n",
    "\n",
    "// Makes sure no more counts come through.\n",
    "go func() {\n",
    "    comms.Send(toFrontEnd, 10)\n",
    "    time.Sleep(500 * time.Millisecond)\n",
    "    fmt.Printf(\"closed\\n\")\n",
    "    listen.Close()\n",
    "}()\n",
    "\n",
    "if counter, ok := <-listen.C; ok {\n",
    "    fmt.Fprintf(os.Stderr, \"Unexpected counter %d received !?\\n\", counter)\n",
    "}\n",
    "fmt.Printf(\"done\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6da3d6a5-25e0-477e-8df7-1f8baa12f97a",
   "metadata": {},
   "source": [
    "### Test `AddressChan[T].LatestOnly`\n",
    "\n",
    "We'll send values faster than we read them, and we want to check that we read always the latest -- and don't get blocked."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "bfd09615-0767-4157-9d6d-70d9e0be7c7a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": []
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ok\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "// Set timeout for program.\n",
    "go func() { \n",
    "    time.Sleep(2 * time.Second)\n",
    "    fmt.Println(\"timedout\")\n",
    "    os.Exit(1)\n",
    "}() \n",
    "\n",
    "listen := comms.Listen[int](toCell).LatestOnly()\n",
    "for ii := 0; ii <= 3; ii ++ {\n",
    "    // Send 3 values from the front-end.\n",
    "    dom.TransientJavascript(fmt.Sprintf(`\n",
    "(() => {\n",
    "    let gonb_comm = globalThis?.gonb_comm;\n",
    "    if (gonb_comm) {\n",
    "        gonb_comm.send(\"%s\", %d);\n",
    "    }\n",
    "})();\n",
    "`, toCell, ii))\n",
    "    time.Sleep(100 * time.Millisecond)\n",
    "}\n",
    "\n",
    "time.Sleep(500 * time.Millisecond)\n",
    "latest := <-listen.C\n",
    "if latest == 3 {\n",
    "    fmt.Println(\"ok\")\n",
    "} else {\n",
    "    fmt.Printf(\"error: received %d\\n\", latest)\n",
    "}\n",
    "listen.Close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94d2ea82-cb92-43e4-84bf-d34c70918b83",
   "metadata": {},
   "source": [
    "#### Make Last Cell Quick To Execute"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "48408597-7822-44e5-935a-04e23121e029",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "No more.\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "fmt.Println(\"No more.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Go (gonb)",
   "language": "go",
   "name": "gonb"
  },
  "language_info": {
   "codemirror_mode": "",
   "file_extension": ".go",
   "mimetype": "text/x-go",
   "name": "go",
   "nbconvert_exporter": "",
   "pygments_lexer": "",
   "version": "go1.25.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
